home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Messaging / OSL / OSLEvals.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  28.6 KB  |  1,029 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        OSLEvals.c
  3.  
  4.     Contains:    
  5.  
  6.     Owned by:    Nick Pilch
  7.  
  8.     Copyright:    © 1992 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <6>     9/26/96    JP        1323103: Disabled marking
  13.          <5>     7/27/96    JP        1372873: Backed out marking fix by
  14.                                     undefining MARKING_FIX
  15.          <3>     6/20/96    JP        1323103: Fixed marking (but no definitive
  16.                                     test cases yet)
  17.          <2>     1/15/96    TJ        Cleaned Up
  18.          <6>     6/22/95    NP        1261016: Don't call OSLDiposeToken when
  19.                                     adding tokens to a list.
  20.          <5>     6/20/95    NP        1252761: Restore context around a whose
  21.                                     clause.
  22.          <4>     6/13/95    eeh        1252761: whose clauses reset context
  23.                                     (disabled)
  24.          <3>     1/12/95    jpa        Don't use obsolete Toolbox names [1211211]
  25.          <2>     8/19/94    NP        1181622: Ownership fix.
  26.          <9>      5/5/94    eeh        bug #1160654: fix for SCPP
  27.          <8>      5/2/94    eeh        bug #1160654: various PPC native changes
  28.          <7>     3/23/94    NP        1143046-unitialized local variable.
  29.          <6>    10/18/93    NP        Added mark functions callback support for
  30.                                     OpenDoc.
  31.          <5>    10/11/93    NP        Removed stuff added previously for tokens.
  32.                                     Changed count and compare callback
  33.                                     dispatching.
  34.          <4>     8/18/93    NP        Changed MakeNullToken
  35.          <3>     8/16/93    NP        Adjusted for latest OSL proposal.
  36.          <2>     7/28/93    NP        Mods for new token type, OSLToken.
  37.          <1>     7/21/93    NP        first checked in
  38.  
  39.     To Do:
  40. */
  41.  
  42. #include "OSLPriv.h"
  43. #include <ToolUtils.h>
  44.  
  45. #define UNUSED(x)    ((void) &x)
  46.  
  47. //#define MARKING_FIX
  48.  
  49. #pragma segment AEObjSuppt
  50.  
  51. void
  52. MakeNull( AEDesc *theDesc )
  53. {
  54.     theDesc->descriptorType = typeNull ;
  55.     theDesc->dataHandle = NULL ;
  56. }
  57.     
  58. void
  59. MakeNullToken( OSLToken *theToken )
  60. {
  61.     theToken->descriptorType = typeNull ;
  62. //    theToken->context = 0 ;
  63.     theToken->dataHandle = NULL ;
  64. }
  65.     
  66.  
  67. static OSErr EvalTerm( Term t , DescType exmnClass, OSLToken *objBeingExamined ,
  68.         short appDoesFlags) ;
  69.  
  70.  
  71. /*———————————————————————— EvalCompare ————————————————————————*/
  72.  
  73. /*evaluates a comparison*/
  74.  
  75. static OSErr
  76. EvalCompare( Comparison  c , DescType  exmnClass ,
  77.         OSLToken  *objBeingExamined , short appDoesFlags)
  78. {
  79.     Boolean              compResult ;
  80.     
  81.     OSErr err = noErr ;
  82.     if ( (*c)->redo )
  83.     {
  84.         FailErr( EvalObj( (*c)->obj1, exmnClass, objBeingExamined, 
  85.             appDoesFlags ), err, errExit ) ;        /* eval first object */
  86.         FailErr( EvalObj( (*c)->obj2, exmnClass, objBeingExamined,
  87.             appDoesFlags ), err, errExit ) ;        /* eval second object */
  88.          
  89.          // compare em
  90.          FailErr( NewCallCompareProc( (*c)->oper, (*((*c)->obj1))->objValue,
  91.             (*((*c)->obj2))->objValue, &compResult ), err, errExit  ) ;
  92.         (*c)->value = compResult ;
  93.  
  94.         // set redo flag if either object must redo
  95.         (*c)->redo = (*((*c)->obj1))->objRedo
  96.                 || (*((*c)->obj2))->objRedo ;
  97.     }
  98.  
  99. FAIL_ERR_PROC(err, errExit)
  100.     if ( SetErrDesc( (*c)->theCompInput ) )        // 4/5. So doesn't dispose later */
  101.         (*c)->theCompInput.dataHandle = NULL ; 
  102. END_FAIL_ERR_PROC(err)
  103.  
  104.  
  105.  
  106. } /* EvalCompare */
  107.  
  108.     /*———————————————————————— EvalLogical ————————————————————————*/
  109.  
  110. static OSErr
  111. EvalLogical( Logical l , DescType  exmnClass ,
  112.         OSLToken *objBeingExamined , short appDoesFlags )
  113. {
  114.     Term          thisTerm ;
  115.     Boolean thisTermVal  ;
  116.     Boolean          terminateCond ;
  117.     OSErr err = noErr;
  118.     
  119.     HLock((Handle)l) ;
  120. //    WITH l** DO
  121.     {
  122.         LogicalPtr lp = *l ;
  123.         if ( lp->redo )
  124.         {
  125.         
  126.         if ( lp->logicalOp == kAEAND )
  127.             terminateCond = false ;
  128.         else if ( lp->logicalOp == kAEOR )
  129.             terminateCond = true ;
  130.         else if ( lp->logicalOp != kAENOT )        /* if ( not, don't care what term value is */
  131.             FailErr( errAENoSuchLogical, err, errExit ) ;
  132.         
  133.         /* Grab the first term, then loop through evaluating them.
  134.         kAENot must have exactly one term; OR and AND may have any number,
  135.         including 0. */
  136.         
  137.         thisTerm = lp->firstTerm ;
  138.         if ( (lp->logicalOp == kAENOT)
  139.                 && ((thisTerm == NULL) || ((*thisTerm)->next != NULL)) )
  140.             FailErr( errAEWrongNumberArgs , err, errExit ) ;
  141.         
  142.         while( thisTerm != NULL )
  143.         {
  144.             FailErr( EvalTerm( thisTerm, exmnClass, objBeingExamined,
  145.                     appDoesFlags ), err, errExit ) ;
  146.             thisTermVal = (*thisTerm)->value ;
  147.             lp->redo |= (*thisTerm)->redo ;
  148.         
  149.             if ( thisTermVal == terminateCond )
  150.                 break ;
  151.         
  152.             thisTerm = (*thisTerm)->next ;
  153.         } /* while */
  154.         
  155.         if ( lp->logicalOp == kAENOT )
  156.             lp->value = !thisTermVal ;
  157.         else
  158.             lp->value = thisTermVal ;        // This works for either way out of the loop */
  159.         
  160.         }
  161.     }
  162.     HUnlock((Handle)l);
  163.  
  164. FAIL_ERR_PROC(err, errExit)
  165.     if ( (l != NULL) && (SetErrDesc( (*l)->theLogicalInput )) )                /* 4/5. So doesn't dispose later */
  166.         (*l)->theLogicalInput.dataHandle = NULL ;
  167. END_FAIL_ERR_PROC(err)
  168.  
  169.  
  170. } /*EvalLogical*/
  171.  
  172.     /*———————————————————————— EvalObj ————————————————————————*/
  173.  
  174. OSErr
  175. EvalObj( Object o, DescType  exmnClass, OSLToken *objectBeingExmn,
  176.         short appDoesFlags )
  177. {
  178.     Boolean              ignoreBool ;
  179.     OSErr err = noErr;
  180.     
  181.     UNUSED(appDoesFlags) ;
  182.     
  183.     if ( (*o)->objRedo )
  184.     {
  185.         HLock( (Handle)o ) ;
  186. //        WITH o** DO
  187.         {
  188.             ObjRecordPtr op = *o ;
  189. //            FailErr( iAEDisposeToken( objValue ) ) ;
  190.             FailErr( InternalResolve( o, exmnClass, 
  191.                 objectBeingExmn, &ignoreBool, &op->objValue, &op->objRedo),
  192.                 err, errExit ) ;
  193.         }
  194.         HUnlock((Handle)o);
  195.     }
  196.  
  197. FAIL_ERR_PROC(err, errExit)
  198.     if ( (o != NULL) && (SetErrDesc( (*o)->theObjInput )) )                /* 4/5. So doesn't dispose later */
  199.         (*o)->theObjInput.dataHandle = NULL ; 
  200. END_FAIL_ERR_PROC(err)
  201.  
  202. } /*EvalObj*/
  203.  
  204.  
  205. #define kKeyExmnClass    ((DescType)'exmn')
  206.  
  207.  
  208.  
  209. static OSErr
  210. EvalCompareEvnt( CompareEvent cevt, DescType exmnClass,
  211.         OSLToken *objBeingExamined )
  212. {
  213.     OSLToken prevExmn ;
  214.     AESendMode sendMode = kAEWaitReply ;
  215.     AESendPriority sendPriority = kAENormalPriority;
  216.     AppleEvent reply ;
  217.     DescType returnedType ;
  218.     long actualSize ;
  219.     Boolean trueOrFalse ;
  220.     OSErr err = noErr ;
  221.     
  222.     prevExmn.dataHandle = NULL ;
  223.     reply.dataHandle = NULL ;
  224.  
  225.     FailErr( GetExmn( &prevExmn ), err, errExit ) ; 
  226.     FailErr( SetExmn( objBeingExamined ), err, errExit ) ; 
  227.     
  228.     // send the event
  229.     HLock( (Handle) cevt ) ;
  230.     FailErr( AEPutParamPtr( &(*cevt)->eventWParams, kKeyExmnClass, typeType,
  231.                (Ptr)&exmnClass, sizeof(exmnClass) ), err, errExit ) ;
  232.     FailErr( AESend( &(*cevt)->eventWParams, &reply, sendMode, sendPriority,
  233.             kNoTimeOut, NULL, NULL ), err, errExit ) ;
  234.     HUnlock( (Handle) cevt ) ;
  235.  
  236.     // get the true or false info
  237.     FailErr( AEGetParamPtr( &reply, keyDirectObject, typeBoolean, &returnedType,
  238.             (Ptr)&trueOrFalse, sizeof(trueOrFalse), &actualSize), err, errExit ) ;
  239.  
  240.     (*cevt)->value = trueOrFalse ;
  241.  
  242.     FailErr( SetExmn( &prevExmn ), err, errExit ) ; 
  243.  
  244. FAIL_ERR_PROC(err, errExit)
  245.     if ( prevExmn.dataHandle )
  246.         CIgnoreOSErr( SetExmn( &prevExmn ) ) ; 
  247.     if ( reply.dataHandle )
  248.         IgnoreOSErr( AEDisposeDesc(&reply) ) ; 
  249. END_FAIL_ERR_PROC(err)
  250. }
  251.  
  252.  
  253.  
  254.  
  255.     /*———————————————————————— EvalTerm ————————————————————————*/
  256.  
  257. static OSErr
  258. EvalTerm( Term t , DescType exmnClass, OSLToken *objBeingExamined ,
  259.         short appDoesFlags)
  260. {
  261. //    AEDesc              saveDesc
  262.  
  263.     OSErr err = noErr;
  264.  
  265. //        saveDesc = objBeingExamined ;        */
  266.     HLock((Handle)t);
  267.     if ( (*t)->redo )
  268.     {
  269.         switch ( (*t)->ttype )
  270.         {
  271.             case kCompare :
  272.                 FailErr( EvalCompare( (*t)->u.compar, exmnClass,
  273.                         objBeingExamined, appDoesFlags), err, errExit ) ;
  274.                 (*t)->redo = (*((*t)->u.compar))->redo;
  275.                 (*t)->value = (*((*t)->u.compar))->value ;
  276.                 break ;
  277.  
  278.             case kCompareEvt :
  279.                 FailErr( EvalCompareEvnt( (*t)->u.cEvt, exmnClass, objBeingExamined ),
  280.                         err, errExit ) ;
  281.                 (*t)->redo = (*((*t)->u.cEvt))->redo ;
  282.                 (*t)->value = (*((*t)->u.cEvt))->value ;
  283.                 break ;
  284.  
  285.             case kLogical :
  286.                 FailErr( EvalLogical( (*t)->u.log, exmnClass, objBeingExamined,
  287.                         appDoesFlags), err, errExit ) ;
  288.                 (*t)->redo = (*((*t)->u.log))->redo;
  289.                 (*t)->value = (*((*t)->u.log))->value ;
  290.  
  291.         }
  292.     
  293. //        if ( (*t)->value )
  294. //            objBeingExamined = saveDesc ;
  295. //        else
  296. //            FailErr( iAEDisposeToken( saveDesc ) ) ;
  297.     }
  298.     HUnlock((Handle)t);
  299.  
  300. FAIL_ERR_PROC(err, errExit)
  301.     if ( ( t != NULL) && (SetErrDesc( (*t)->theTermInput )) )        /* 4/5. So doesn't dispose later */
  302.         (*t)->theTermInput.dataHandle = NULL ;
  303. END_FAIL_ERR_PROC(err)
  304.  
  305. } /*EvalTerm*/
  306.  
  307.  
  308. ////////////////////////////////////////////////////////////////////////////////////
  309. //
  310. //        EvalWhose() and its service routines
  311. //
  312. ////////////////////////////////////////////////////////////////////////////////////
  313.  
  314.  
  315. // for the C port, I'm adding this struct to pass the variables that the various
  316. // EvalWhose service routines have access to by virtue of being nested inside
  317. // EvalWhose() in the Pascal version.
  318.  
  319. //CONST
  320. //kNumDescsToAdd == 20 ;            /* descriptors stored in a Handle: when it's full, resize by this number */
  321. //kStoreAllSuccesses == 0 ;    /* special value for numToStore meaning infinite */
  322. //TYPE
  323. typedef AEDesc *DescArrayPtr, **DescArrayHandle ;
  324.  
  325. typedef OSLToken *OSLTokenPtr, **OSLTokenHandle ;
  326.  
  327. typedef struct WHG {            // EvalWhoseGlobals
  328.     OSLToken         tempList ;        // see EvalWhose for some comments about these
  329.     OSLToken         markToken ;                    // vars
  330.     OSLTokenHandle          theDescArrayH ;
  331.     long          nSuccesses ;
  332.     long          numInStorage ;            
  333.     Boolean          isARange ;
  334.     Boolean          hasRelative ;
  335.     Boolean          mark ;
  336.     Boolean          goingBackward ;
  337.     Boolean          mustReturnList ;
  338.     
  339.     Whose w ;            // this is a formal: has to be added too though
  340.     } WHG ;
  341.  
  342.  
  343. static OSErr
  344. DisposeDescArray( OSLTokenPtr startDesc, long nToDispose )
  345. {
  346.     OSLTokenPtr stopDesc ;
  347.     OSErr err = noErr ;
  348.  
  349.     stopDesc = startDesc + nToDispose ;
  350.     while ( startDesc < stopDesc  )
  351.     {
  352.         FailErr( iAEDisposeToken( startDesc ), err, errExit ) ;
  353.         ++startDesc ;
  354.     }
  355.  
  356. FAIL_ERR_PROC(err, errExit)
  357. END_FAIL_ERR_PROC(err)
  358. }
  359.  
  360. #ifdef MARKING_FIX
  361. static OSErr
  362. InitMarking( DescType containerClass, OSLToken container, WHG *wg )
  363. {
  364.     OSLContext    curContext;
  365.     short        appDoesFlags;
  366.     OSErr        err;
  367.     
  368.     FailErr (GetCurrentContext(&curContext), err, errExit);
  369.     FailErr (GetAppDoesFlags(&curContext, &appDoesFlags), err, errExit);
  370.     // this code shouldn't be enabled because we disabled MARKING_FIX
  371.     // and make mark always be false, even here just in case.  :)
  372.     wg->mark = false; //(appDoesFlags & kAEIDoMarking) != 0 ;
  373.     if ( wg->mark )
  374.     {
  375.         FailErr( NewCallGetMarkToken( container, containerClass, &wg->markToken ),
  376.                 err, errExit ) ;
  377.     }
  378.     else
  379.     {
  380.         wg->theDescArrayH = (OSLTokenHandle)NewHandle( 0 ) ; /* sizeof(AEDesc) )) ;*/
  381.         FailErr( MemError(), err, errExit ) ;
  382.     }
  383.         
  384.     
  385. FAIL_ERR_PROC(err, errExit)
  386. END_FAIL_ERR_PROC(err)
  387. }    // InitMarking
  388. #endif
  389.  
  390. static OSErr
  391. RedoListOrMark( long realStart, long realStop, WHG *wg )
  392. {
  393.     long                 temp ;
  394.     long                  sizeSought ;
  395.     OSLTokenPtr          theDescArrP ;
  396.     OSErr err = noErr ;
  397.  
  398.     if ( wg->numInStorage < realStop )
  399.         FailErr( errAENoSuchObject, err, errExit ) ; /* was errInvalidOffset */
  400.  
  401.     if ( realStart > realStop )            // 2/18. if we wanted the 20th and there are only 19, error
  402.     {
  403.         if ( wg->isARange && wg->hasRelative
  404.                 && ((*(wg->w))->index.startCase == kAEAny)
  405.                 && ((*(wg->w))->index.stopCase == kAEAny) )        // special case for
  406.                                                                 // any to any range 
  407.         {
  408.             temp = realStart ;
  409.             realStart = realStop ;
  410.             realStop = temp ;
  411.         }
  412.         else if ( !(wg->mustReturnList) )
  413.             FailErr( errAENoSuchObject, err, errExit ) ;    // was errInvalidOffset
  414.     }
  415.  
  416.     if ( wg->mark )
  417.     {
  418.         FailErr( NewCallAdjustMarks( realStart, realStop, wg->markToken ),
  419.                 err, errExit ) ;
  420.     }
  421.     else
  422.     {            // ok if ( realStart > realStop b/c just disposing null tokens 
  423.         HLock( (Handle)wg->theDescArrayH ) ;
  424.         theDescArrP = *(wg->theDescArrayH) ;
  425.         
  426.         /* First, allow client to dispose of all the tokens we won't include in the result */
  427.         
  428.         if ( realStart > 1 )
  429.             FailErr( DisposeDescArray( theDescArrP, realStart-1 ),
  430.                 err, errExit ) ;
  431.         
  432.         if ( wg->numInStorage > realStop )
  433.             FailErr( DisposeDescArray( &theDescArrP[realStop] ,
  434.                     wg->numInStorage - realStop ), err, errExit ) ;
  435.         
  436.         /* calc the number of bytes the final array of AEDesc ought to contain */
  437.         wg->numInStorage = realStop - realStart + 1 ;
  438.         sizeSought = wg->numInStorage * sizeof(AEDesc) ;
  439.         
  440.         /* shif (t what we want to keep to the start of the block. Don't bother if ( already there.
  441.         No need to check sizeSought>0 b/c BlockMove bails if ( negative. */
  442.         if ( realStart > 1 )
  443.         BlockMove( theDescArrP + realStart - 1, (Ptr)theDescArrP, sizeSought ) ;
  444.         
  445.         HUnlock( (Handle)wg->theDescArrayH ) ;
  446.         SetHandleSize( (Handle)wg->theDescArrayH, sizeSought ) ;
  447.     }
  448.  
  449. FAIL_ERR_PROC(err, errExit)
  450. END_FAIL_ERR_PROC(err)
  451.  
  452. } /* RedoListOrMark */
  453.  
  454.  
  455.  
  456. static OSErr
  457. MarkOrRemember( OSLToken  dToken , long index, DescType containerClass, OSLToken container, WHG *wg  )
  458. {
  459.     long                  offset  ;
  460.     OSErr err = noErr ;
  461.     
  462. #ifdef MARKING_FIX
  463.     if (wg->numInStorage == 0)
  464.         InitMarking(containerClass, container, wg);
  465. #endif
  466.  
  467.     if ( wg->mark )
  468.     {
  469.         FailErr( NewCallMark( dToken, wg->markToken, index ), err, errExit ) ;
  470.     
  471.         /* <eeh> The app has passed me what is most
  472.         likely a fresh descriptor with a unique reference to a relocatable block.
  473.         if ( I don't dispose of it before reusing the variable the heap will fill
  474.         up, yet this may send the wrong message to the app.  I am NOT done with
  475.         the reference to the app's object. */
  476.     }
  477.     else
  478.     {
  479.         if ( wg->goingBackward )                /* we want to store in reverse order */
  480.             offset = 0 ;
  481.         else
  482.             offset = GetHandleSize( (Handle)wg->theDescArrayH ) ;
  483.         
  484.         Munger( (Handle)wg->theDescArrayH, offset, NULL, 0, &dToken, sizeof( dToken ) ) ;
  485.         FailErr( MemError(), err, errExit ) ;
  486.     }
  487.     ++wg->numInStorage ;
  488.  
  489. FAIL_ERR_PROC(err, errExit)
  490. END_FAIL_ERR_PROC(err)
  491. } /* MarkOrRemember */
  492.  
  493.  
  494.  
  495. /*————————————*/
  496. static OSErr        
  497. ResultDescriptor( OSLToken *result, WHG *wg )
  498. {
  499.     long                  i ;
  500.     OSLTokenPtr         nextDesc ;
  501.     OSErr err = noErr ;
  502.  
  503.     if ( wg->mark )
  504.     {
  505.         *result = wg->markToken ;
  506.     }
  507.     
  508.     else
  509.     {
  510.         if ( (wg->numInStorage == 1) && !wg->mustReturnList )
  511.             *result = **(wg->theDescArrayH) ;
  512.         else
  513.         {
  514.             FailErr( AECreateList( NULL, 0, false, &wg->tempList ), err, errExit ) ;
  515.             
  516.             /* <eeh> here we put the tokens into a recognizable form -- an AEList.
  517.               BUT NOTE: we are creating copies of the app's tokens.  if ( we do not
  518.               dispose of the descriptors after putting them in the list they will
  519.               live in memory forever, yet to dispose is to say to the app that
  520.               we are done with them when in fact we are not.
  521.               So call AEDisposeDesc on them.  The app can dispose of them correctly
  522.               (as tokens) when it gets the resulting list back. */
  523.             
  524.             HLock( (Handle)wg->theDescArrayH ) ;
  525.             nextDesc = *(wg->theDescArrayH) ;
  526.             for( i = 1;  i <= wg->numInStorage; ++i )
  527.             {
  528.                 FailErr( AEPutDesc( &wg->tempList, i, nextDesc ), err, errExit ) ;
  529.                 IgnoreOSErr( AEDisposeDesc( nextDesc ) ) ;
  530.                 ++nextDesc ;
  531.             }
  532.  
  533.             *result = wg->tempList ;
  534.         }
  535.  
  536.         DisposeHandle( (Handle)wg->theDescArrayH ) ;
  537.     }
  538.  
  539. FAIL_ERR_PROC(err, errExit)
  540. END_FAIL_ERR_PROC(err)
  541. } // ResultDescriptor
  542.  
  543.  
  544.  
  545.  
  546. ////////////////////////////////////////////////////////////////////////////////////
  547. // AfterFirst()
  548. // determines whether a given n is >== the start of the range of
  549. // successes desired
  550. ////////////////////////////////////////////////////////////////////////////////////
  551. #define ABS(n)    ((n)>=0?(n):-(n))
  552. static Boolean
  553. AfterFirst( long n, WHG *wg )
  554. {
  555.     Boolean rval =  true ;
  556.     
  557.     //WITH (*w)->index DO
  558.     {
  559.         indexRecordPtr ip = &(*(wg->w))->index ;
  560.         if ( (ip->startCase == typeLongInteger) )
  561.         {
  562.             if ( wg->goingBackward )
  563.                 rval =  ABS(n) >= ABS(ip->stopValue) ;
  564.             else
  565.                 rval =  ABS(n) >= ABS(ip->startValue) ;
  566.         }
  567.     }
  568.     return rval ;
  569. }
  570.  
  571.  
  572. ////////////////////////////////////////////////////////////////////////////////////
  573. // BeforeLast()
  574. // determines whether a given n is <= the end of the range of successes
  575. // desired
  576. ////////////////////////////////////////////////////////////////////////////////////
  577. static Boolean
  578. BeforeLast( long n, WHG *wg )
  579. {
  580.     Boolean rval =  true ;
  581.     
  582.     // WITH (*w)->index DO
  583.     {
  584.         indexRecordPtr ip = &(*(wg->w))->index ;
  585.         if ( (ip->stopCase == typeLongInteger)    )
  586.         {
  587.             if ( n >= 0 )                /* we are counting up: use stop as last */
  588.             {
  589.                 if ( ip->stopValue > 0 )
  590.                     rval =  n <= ip->stopValue ;
  591.                 else
  592.                     rval =  true ;        /* we have to save all of them above start to do negative index */
  593.             }
  594.             else                                    /* we are counting down: use start as last -- MUST be negative */
  595.                 rval =  n >= ip->startValue ;        /* both are negative */
  596.         }
  597.     }
  598.     return rval ;
  599. }
  600.  
  601. ////////////////////////////////////////////////////////////////////////////////////
  602. // ResolveSingle()
  603. ////////////////////////////////////////////////////////////////////////////////////
  604.  
  605.  
  606. static long
  607. Middle( long n )
  608. {
  609.     return n+1 >> 1 ;        // better than BITSHIFT and DIV 2
  610. }
  611.  
  612. extern long MyLongMod( long l1, long l2) ;
  613.  
  614. // Choose a random number from 1 to n
  615. static long
  616. JRandomNumber( long n )
  617. {
  618.     long randomLong ;
  619.     if ( n != 0 )
  620.     {
  621.         randomLong = ((long)Random()) << 16 ;
  622.         randomLong |= Random() ;
  623. //        return ABS( MyLongMod( randomLong, n ) ) + 1 ;
  624.         randomLong %= n ;
  625.         return (randomLong >= 0? randomLong : -randomLong ) + 1;
  626.     }
  627.     else
  628.         return 0 ;
  629. }
  630.  
  631. static OSErr
  632. ResolveSingle( DescType theCase, long *result, WHG *wg ) 
  633. {
  634.     OSErr err = noErr ;
  635.  
  636.     if ( theCase == kAEMiddle )
  637.         *result = Middle( wg->nSuccesses ) ;
  638.     else if ( theCase == kAEAny )
  639.         *result = JRandomNumber( wg->nSuccesses ) ;
  640.     else
  641.         FailErr( errAEImpossibleRange, err, errExit ) ;
  642.  
  643. FAIL_ERR_PROC(err, errExit)
  644. END_FAIL_ERR_PROC(err)
  645. } // ResolveSingle
  646.  
  647. ////////////////////////////////////////////////////////////////////////////////////
  648. // ResolveToInteger()
  649. ////////////////////////////////////////////////////////////////////////////////////
  650. static OSErr
  651. ResolveToInteger( long *realStart, long *realStop, WHG *wg )
  652. {
  653.     OSErr err = noErr ;
  654.  
  655.     // WITH (*w)->index DO            /* EvalWhose locks the whose record down */
  656.     {
  657.         indexRecordPtr ip = &(*(wg->w))->index ;
  658.         
  659.         if ( wg->hasRelative && !wg->isARange )            /* isn't going backward, and will have saved all successes;
  660.                                                                         no longs or negative longs (UNLESS marking is in use!!!) */
  661.         {
  662.             if ( ip->startCase == kAEAll )
  663.             {
  664.                 *realStart = 1 ;
  665.                 *realStop = wg->numInStorage ;        /* same as wh->nSuccesses */
  666.             }
  667.             else if ( ip->startCase == typeLongInteger )        /* only possible if ( we're doing marking,... */
  668.             {                                                                            /* ...which will have caused us to save all successes */
  669.                 if ( ip->startValue > 0 )
  670.                     *realStart = ip->startValue ;
  671.                 else
  672.                     *realStart = wg->numInStorage + ip->startValue + 1 ;
  673.                 *realStop = *realStart ;
  674.             }
  675.             else 
  676.             {        /* any, middle */
  677.                 long temp ;
  678.                 FailErr( ResolveSingle( ip->startCase, &temp, wg ), err, errExit ) ; 
  679.                 *realStop = *realStart = temp ;
  680.             }
  681.         }
  682.         else if ( wg->isARange )
  683.         {
  684.             if ( ip->startCase == typeLongInteger )
  685.             {
  686.                 if ( (ip->startValue > 0) || wg->goingBackward )
  687.                     *realStart = 1 ;
  688.                 else
  689.                     *realStart = wg->numInStorage + ip->startValue + 1 ;
  690.             }
  691.             else
  692.             {        /* any, middle */
  693.                 long temp ;
  694.                 FailErr( ResolveSingle( ip->startCase, &temp, wg ), err, errExit ) ; 
  695.                 *realStart = temp ;
  696.             }
  697.             
  698.             if ( ip->stopCase == typeLongInteger )
  699.             {
  700.                 if ( ip->stopValue >= 0 )
  701.                 {
  702.                     if ( ip->startValue >= 0 )    
  703.                         *realStop = ip->stopValue - ip->startValue + 1 ;
  704.                     else
  705.                         *realStop = ip->stopValue ;
  706.                 }
  707.                 else
  708.                 {
  709.                     if ( ip->stopValue >= 0 )    
  710.                         *realStop = wg->numInStorage + ip->stopValue + 1 ;
  711.                     else if ( wg->goingBackward )            // same as IF mark THEN
  712.                         *realStop = wg->numInStorage ;
  713.                     else
  714.                         *realStop = wg->numInStorage + ip->stopValue + 1; /* added 4/1 */
  715.                 }
  716.             }
  717.             else        /* any, middle */
  718.             {
  719.                 long temp ;
  720.                 FailErr( ResolveSingle( ip->stopCase, &temp, wg ), err, errExit ) ; 
  721.                 *realStop = temp ;
  722.             }
  723.         }
  724.         else                /* must be a single index; positive or negative doesn't matter, as there should */
  725.         {            /*    be only one in storage anyway.  if ( there aren't any in storage, we've an */
  726.             if ( wg->numInStorage == 1 )                    /* error.  Get the 3nd n when there are only 2 ns will */
  727.             {                                                        /* produce such a case.            */
  728.                 *realStart = *realStop = 1 ;
  729.             }
  730.             else
  731.             {
  732.     //            PAssert( wg->numInStorage == 0, 'wg->numInStorage != 0' ) ;
  733.                 FailErr( errAENoSuchObject, err, errExit ) ;
  734.             }
  735.         }
  736.     }        /*with*/
  737.  
  738. FAIL_ERR_PROC(err, errExit)
  739. END_FAIL_ERR_PROC(err)
  740. } /* ResolveToInteger*/
  741.             
  742.  
  743.  
  744.  
  745.     /*———————————————————————— EvalWhose ————————————————————————*/
  746. /*evaluates a Whose term*/
  747.  
  748. OSErr
  749. EvalWhose( Whose whoz , DescType  wantClass , DescType  containerClass ,
  750.         OSLToken  container , short appDoesFlags )
  751. {
  752.     long         nElements ;
  753.     long         realStart ;
  754.     long         realStop ;
  755.     AEDesc         dIth ;            /* descriptor holding selection data for i-th element */
  756. //    long         i ;
  757.     OSLToken     dThisElement ;
  758. //    AEDesc         tempList ;            /* used where more than one result to be returned; dispose only on error */
  759. //    AEDesc         markToken ;            /* change markID to descriptor 1/10; dispose only in FailErr */
  760. //    DescArrayHandle          theDescArrayH ;
  761. //    long          nSuccesses ;
  762. //    long          numInStorage ;            /* used for marked case and unmarked: always <== nSuccesses, as excluded those cases outside of range */
  763.     long          searchStart ;
  764.     long          searchEnd ;
  765.     long          incrementer ;
  766. //    Boolean          isARange ;
  767. //    Boolean          isFromEnd ;
  768. //    Boolean          hasRelative ;
  769. //    Boolean          mark ;
  770. //    Boolean          goingBackward ;
  771. //    Boolean          mustReturnList ;
  772.     WHG                whg ;
  773.     OSErr err = noErr;
  774. #define USE_TEMP_CONTEXT_CHANGE
  775. #ifdef USE_TEMP_CONTEXT_CHANGE
  776.     OSLContext savedCurContext;
  777. #endif
  778.  
  779.     if (appDoesFlags & kAEIDoMarking != 0) {
  780.         DebugStr("\pOpenDoc does not support marking.  I'm turning it off.");
  781.         appDoesFlags &= ~kAEIDoMarking;
  782.     }
  783.     whg.w = whoz ;
  784. #ifndef MARKING_FIX
  785.     // the marking fix didn't work, so we're just disallowing marking
  786.     whg.mark = false;    //(appDoesFlags & kAEIDoMarking) != 0 ;
  787. #endif
  788.     MakeNullToken( &whg.markToken ) ;
  789.     MakeNullToken( &dThisElement ) ;
  790.     whg.nSuccesses = 0 ;
  791.     whg.tempList.dataHandle = NULL ;
  792.     dIth.dataHandle = NULL ;
  793.     whg.theDescArrayH = NULL ;
  794.  
  795.     HLock( (Handle)whg.w ) ;
  796.  
  797.     // WITH whg.w** DO
  798.     {
  799.         WhoseRecordPtr wp = *whg.w ;
  800.         whg.isARange = wp->index.stopCase != typeNull;    // are we looking 
  801.                                                     // for a range or one?
  802.         
  803.         if ( whg.isARange )
  804.         //WITH index DO
  805.         {
  806.             indexRecordPtr ip = &wp->index ;
  807.             if ( ip->stopCase == typeLongInteger )
  808.                 if ( ip->startCase == typeLongInteger )
  809.                     if ( (ip->startValue > 0) && (ip->stopValue > 0)
  810.                             && (ip->startValue > ip->stopValue)
  811.                             || ((ip->startValue < 0) && (ip->stopValue < 0)
  812.                             && (ip->startValue > ip->stopValue)) )
  813.                         FailErr( errAEImpossibleRange, err, errExit ) ;
  814.         }
  815.     
  816.         FailErr( NewCallCountProc( wantClass, containerClass, container,
  817.                 &nElements ), err, errExit ) ;
  818.                 
  819.         // This code would prevent infinite loop/crash for case where 
  820.         // CallCountProc returns negative value.
  821.         
  822.         if ( nElements < 0 )                    /* equal to 0 may be ok: may want to return empty list rather than error */
  823.             FailErr( errAENegativeCount, err, errExit ) ;
  824.         
  825. #ifndef MARKING_FIX
  826.         // moved to InitMarking (above)
  827.         if ( whg.mark )
  828.         {
  829.             FailErr( NewCallGetMarkToken( container, containerClass, &whg.markToken ),
  830.                     err, errExit ) ;
  831.         }
  832.         else
  833.         {
  834.             whg.theDescArrayH = (OSLTokenHandle)NewHandle( 0 ) ; /* sizeof(AEDesc) )) ;*/
  835.             FailErr( MemError(), err, errExit ) ;
  836.         }
  837. #endif
  838.         whg.numInStorage = 0 ;
  839.  
  840. #ifndef MARKING_FIX
  841.         // we cannot iterate backwards because we don't know if we are going to
  842.         // be marking until we try to MarkOrRemember something.
  843.         
  844.         /* We can iterate backwards for advantage iff 1) not using marking, and 
  845.         2) it is either a negative index or
  846.         a range composed of two negative indices */
  847.         
  848.         whg.goingBackward = (! whg.mark)
  849.                 && (wp->index.startCase == typeLongInteger)
  850.                 && (wp->index.startValue < 0)
  851.                 && ((wp->index.stopCase == typeNull) 
  852.                         || ((wp->index.stopCase == typeLongInteger)
  853.                                 && (wp->index.stopValue < 0))) ;                    
  854. #else
  855.         whg.goingBackward = false;
  856. #endif
  857.         
  858.         whg.mustReturnList = wp->index.startCase == kAEAll ;
  859.         
  860.         // hasRelative really means 'mustStoreAll'; hence it includes the case where
  861.         // we're looking for the -2nd and would be going backwards if mark weren't
  862.         // true
  863.         
  864.         whg.hasRelative = whg.mustReturnList    // was (index.startCase = kAEAll)
  865. #ifndef MARKING_FIX
  866.                 // this clause can't be evaluated since we don't know if marking is on yet
  867.                 || ((wp->index.startCase == typeLongInteger) && (wp->index.startValue < 0)
  868.                     && ((wp->index.stopCase == typeNull)
  869.                         || ((wp->index.stopCase == typeLongInteger)
  870.                             && (wp->index.stopValue < 0)))
  871.                     && whg.mark)
  872. #endif
  873.                 || (wp->index.startCase == kAEAny)
  874.                 || (wp->index.stopCase == kAEAny)
  875.                 || (wp->index.startCase == kAEMiddle)
  876.                 || (wp->index.stopCase == kAEMiddle) ; // tests for  gross cases where 
  877.                                                   // each and every matching element 
  878.                                                   // must be marked or remembered
  879.         
  880.     //                || ((index.startCase == typeLongInteger) && (index.start < 0))
  881.     //                || ((index.stopCase == typeLongInteger) && (index.stop < 0)) ;
  882.         
  883.         // initialize a handy ith element descriptor
  884.         FailErr( AECreateDesc( typeLongInteger, NULL, sizeof(long), &dIth ),
  885.                 err, errExit ) ;
  886.         
  887.         /*
  888.         (relatively) unoptimized whose clause evaluation: ask the app how many of a given class
  889.         it has in the container, and loop through getting each by index and testing.  For those
  890.         that pass: record another success, and check if we are dealing with a range or
  891.         relative.  if a range we don't need to record those that are before or after.  if an
  892.         index we know exactly which we are after and when we're done.
  893.         
  894.         One optimization added: if ( we are after the last n passing the test, we never keep
  895.         track of more than the last n to pass the test.
  896.         */
  897.         if ( whg.goingBackward )
  898.         {
  899.             searchStart = nElements ;
  900.             searchEnd = 0 ;
  901.             incrementer = -1 ;
  902.         }
  903.         else    
  904.         {
  905.             searchStart = 1 ;
  906.             searchEnd = nElements + 1 ;
  907.             incrementer = 1 ;
  908.         } 
  909.     
  910. #ifdef USE_TEMP_CONTEXT_CHANGE
  911.         FailErr( GetCurrentContext( &savedCurContext ), err, errExit );
  912. #endif
  913.  
  914.         while ( searchStart != searchEnd )
  915.         {
  916.             // Get the ith element as objBeingExamined for term
  917.             **(long **)dIth.dataHandle = searchStart ;
  918. #ifdef USE_TEMP_CONTEXT_CHANGE
  919.             // <eeh> added: start each resolution with the same context.
  920.             SetCurrentContext(&savedCurContext);            
  921. #endif
  922.             FailErr( iCallAccessor( wantClass, container, containerClass,
  923.                     formAbsolutePosition, dIth, &dThisElement), err,
  924.                     errExit) ;
  925.             
  926.             // evaluate the term. dThisElement is exmn
  927.             FailErr( EvalTerm( wp->theTerm, wantClass, &dThisElement, appDoesFlags ),
  928.                     err, errExit ) ;
  929.             
  930.             if ( (*(wp->theTerm))->value )
  931.             {
  932.                 whg.nSuccesses += incrementer ;
  933.                 
  934.                 // since could be both a range and relative ("from the second
  935.                 // to the last"), do relative first.  Range will sometimes ignore
  936.                 // cases (those not afterFirst or beforeLast) that need to be 
  937.                 // considered if ( a relative is also involved.
  938.                 
  939.                 if ( whg.hasRelative )
  940.                 {
  941.                     FailErr( MarkOrRemember( dThisElement, whg.nSuccesses, containerClass, container, &whg ),
  942.                             err, errExit ) ;
  943.                 }
  944.                 else if ( whg.isARange )
  945.                 {
  946.                     if ( AfterFirst(whg.nSuccesses, &whg) )
  947.                     {
  948.                         if ( BeforeLast( whg.nSuccesses, &whg ) )
  949.                         {
  950.                             //<eeh> this won't work for whg.nSuccesses < 0
  951.                             FailErr( MarkOrRemember( dThisElement,
  952.                                     whg.nSuccesses-(wp->index.startValue-1), containerClass, container, &whg ),
  953.                                     err, errExit ) ;        
  954.                         }
  955.                         else
  956.                         {
  957.                             whg.nSuccesses -= incrementer ;        // 3/18; back down if ( we don't need this one
  958.                             FailErr( iAEDisposeToken( &dThisElement ),
  959.                                     err, errExit ) ;// 3/23 dispose of it too!
  960.                             break ;            // if ( after last, we are done with this whose
  961.                         }
  962.                         // above because can't put 2nd desc if no 1st
  963.                     }
  964.                     else
  965.                     {
  966.                         FailErr( iAEDisposeToken( &dThisElement ), err, errExit ) ;
  967.                     }
  968.                 }
  969.                 else        // it's a simple index
  970.                 {
  971.                     if ( whg.nSuccesses == wp->index.startValue )
  972.                     {
  973.                         // it is the first, by definition
  974.                         FailErr( MarkOrRemember( dThisElement, 1, containerClass, container, &whg ),
  975.                                 err, errExit ) ;
  976.                         break ;                    // we got it; get out of for loop 
  977.                     }
  978.                     else
  979.                         FailErr( iAEDisposeToken( &dThisElement ), err, errExit ) ;
  980.                 }
  981.             }
  982.             else
  983.                 FailErr( iAEDisposeToken( &dThisElement ), err, errExit ) ;
  984.             
  985.             searchStart += incrementer ;
  986.         } // while
  987.     
  988.         if ( (whg.nSuccesses == 0) && !whg.mustReturnList )    // was <= 0; fixes LLD-UPG-25
  989.             FailErr( errAENoSuchObject, err, errExit ) ;    // fixes LLD-UPG-22 bug: was invalidRelative
  990.         
  991.         FailErr( ResolveToInteger( &realStart, &realStop, &whg ),
  992.                 err, errExit ) ;
  993.         FailErr( RedoListOrMark( realStart, realStop, &whg ), err, errExit ) ;
  994.         
  995.         FailErr( ResultDescriptor( &wp->whoseValue, &whg ), err, errExit) ;
  996.         
  997.         IgnoreOSErr( AEDisposeDesc( &dIth ) );
  998.     
  999.     } // WITH
  1000.     HUnlock((Handle)whg.w);
  1001.  
  1002.  
  1003.  
  1004.  
  1005. FAIL_ERR_PROC(err, errExit)
  1006.     long  i ;
  1007.     if ( (whg.w != NULL) && (SetErrDesc( (*whg.w)->theWhoseInput )) )                /* 4/5. So doesn't dispose later */
  1008.         (*whg.w)->theWhoseInput.dataHandle = NULL ;
  1009.     IgnoreOSErr( AEDisposeDesc( &dIth ) );
  1010.     IgnoreOSErr( InternalDisposeToken( &whg.tempList ) );
  1011.     IgnoreOSErr( iAEDisposeToken( &dThisElement ) ) ;
  1012.  
  1013.     if ( whg.mark )
  1014.         IgnoreOSErr( iAEDisposeToken( &whg.markToken ) ) ;
  1015.     else if ( whg.theDescArrayH != NULL )
  1016.     {
  1017.         for( i = 0; i <= whg.numInStorage-2; ++i )    // 1 because 0-based; another because the i-1th is dThisElement, disposed above */
  1018.         {
  1019.             IgnoreOSErr( iAEDisposeToken( &(*(whg.theDescArrayH))[i] ) ) ;
  1020.         }
  1021.         DisposeHandle( (Handle)whg.theDescArrayH ) ;
  1022.     }
  1023. END_FAIL_ERR_PROC(err)
  1024.  
  1025.  
  1026. } // EvalWhose
  1027.  
  1028.  
  1029.